/* 
 *	Copyright 2014  Yanqing Wu
 *		email: yqwu_yqwu@126.com
 *
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
*/

#include "stdafx.h"
#include "StdCtrlSkinWnd.h"

#include "StdCtrlSkinTool_Utils.h"
#include "StdCtrlSkin.h"
#include "StdCtrlSkinBg.h"

void CStdCtrlSkinWnd::InitDataElt(CStdCtrlSkin* pMgr)
{
	m_pMgr = pMgr;
	m_bg = nullptr;
}
CStdCtrlSkinWnd::CStdCtrlSkinWnd(CStdCtrlSkin* pMgr)
{
	InitDataElt(pMgr);
}
CStdCtrlSkinWnd::CStdCtrlSkinWnd(CComPtr<IXMLDOMNode> spNode, CStdCtrlSkin* pMgr)
{
	InitDataElt(pMgr);
	LoadXmlNode(spNode);
}

CStdCtrlSkinWnd::~CStdCtrlSkinWnd(void)
{
	if ( m_bg )
		delete m_bg;
}

CString CStdCtrlSkinWnd::GetFilePath(void)
{
	return m_pMgr->GetFilePath();
}

bool CStdCtrlSkinWnd::LoadXmlNode(CComPtr<IXMLDOMNode> spNode)
{
	auto attribPairs = StdCtrlSkinTool_XmlGetAttribPairs(spNode);
	auto pEnum = StdCtrlSkinTool_GetEnum();
	CStdCtrlSkin_EnumAttrib attrib;
	for(auto i : attribPairs)
	{
		auto correct = pEnum->Parse(attrib, i.first);
		if ( !correct )
		{
			SetCustomAttrib(i.first, i.second);
			continue;
		}
		switch(attrib)
		{
		case CStdCtrlSkin_EnumAttrib::NAME:
			window_name = i.second;
			break;
		default:
			SetCustomAttrib(i.first, i.second);
			break;
		}
	}
	CComPtr<IXMLDOMNodeList> spChildren;
	spNode->get_childNodes(&spChildren);
	long length;
	spChildren->get_length(&length);
	CStdCtrlSkin_EnumSubNode type;
	CStdCtrlSkinTable* pTable;
	UINT count = 0;
	for(long i=0; i!=length; ++i)
	{
		CComPtr<IXMLDOMNode> spChild;
		spChildren->get_item(i, &spChild);
		auto name = StdCtrlSkinTool_XmlGetNodeName(spChild);
		auto correct = pEnum->Parse(type, name);
		if ( !correct )
			continue;
		switch(type)
		{
		case CStdCtrlSkin_EnumSubNode::BG:
			if ( !m_bg )
				m_bg = new CStdCtrlSkinBg(spChild, this);
			break;
		case CStdCtrlSkin_EnumSubNode::TABLE:
			pTable = new CStdCtrlSkinTable(spChild, this);
			m_table_list[count] = pTable;
			count ++;
			break;
		default:
			break;
		}
	}
	PostLoading();
	return true;
}

void CStdCtrlSkinWnd::SetRect(CRect rect)
{
	//	Now all the tables are placed vertically, so calculate the height only
	auto width = rect.right - rect.left;
	auto height = rect.bottom - rect.top;
	std::map<UINT, UINT> min_height_list;
	std::map<UINT, UINT> weight_list;

	UINT total_weight = 0, total_min_height = 0;
	for(auto i : m_table_list)
	{
		auto size = i.second->GetMinTableSize();
		min_height_list[i.first] = size.cy;
		total_min_height += size.cy;
		weight_list[i.first] = i.second->GetWeight();
		total_weight += weight_list[i.first];
	}
	double incrY = 0;
	if ( total_min_height<height && total_weight>0 )
		incrY = 1.0 * (height - total_min_height) / total_weight;
	CRect tableRect = rect;
	tableRect.bottom = tableRect.top;
	for(auto i : m_table_list)
	{
		tableRect.top = tableRect.bottom;
		tableRect.bottom += min_height_list[i.first] + incrY * weight_list[i.first];
		i.second->SetRect(tableRect);
	}
}

bool CStdCtrlSkinWnd::LogControl(CString ctrlName, CWnd* pCtrl)
{
	bool renamed = false;
	//	Make sure that this control has exactly one log in this window
	for(auto i : m_ctrl_list)
	{
		if ( i.second==pCtrl )
		{
			m_ctrl_list.erase(i.first);
			renamed = true;
		}
	}
	m_ctrl_list[ctrlName] = pCtrl;
	return renamed;
}

bool CStdCtrlSkinWnd::UnlogControl(CWnd* pCtrl)
{
	for(auto i : m_ctrl_list)
	{
		if ( i.second == pCtrl )
		{
			m_ctrl_list.erase(i.first);
			return true;
		}
	}
	return false;
}

void CStdCtrlSkinWnd::PostLoading(void)
{
	//	Generate name 2 cell look up table
	for(auto i : m_table_list)
		i.second->GenerateName2Cell(m_name2cell_list);
}

void CStdCtrlSkinWnd::DoLayOut(CRect rect)
{
	SetRect(rect);
	CRect hiddenRect(-1, -1, -1, -1);
	CRect ctrlRect;
	for(auto i : m_ctrl_list)
	{
		auto name = i.first;
		auto pCtrl = i.second;
		if ( m_name2cell_list.find(name) == m_name2cell_list.end() )
			ctrlRect = hiddenRect;
		else
		{
			auto pCell = m_name2cell_list[name];
			ctrlRect = pCell->GetCtrlRect();
		}
		pCtrl->MoveWindow(ctrlRect);
	}
}

HBITMAP CStdCtrlSkinWnd::GetBitmap(CSize size, HDC hDC)
{
	if ( m_bg )
		return m_bg->GenerateBitmap(size, hDC);
	return NULL;
}

void CStdCtrlSkinWnd::SetBackColor(COLORREF color)
{
	if ( m_bg )
		m_bg->SetBackColor(color);
}

#ifdef __DUMPTEST
void CStdCtrlSkinWnd::Dump(std::ofstream& fio, CStdCtrlSkin_EnumDump type)
{
	CStringA nameA(window_name);
	fio << "Window=" << nameA.GetString() << std::endl;
	CStdCtrlSkin_BaseElt::Dump(fio, type);
	if ( m_bg )
		m_bg->Dump(fio, type);
	for(auto i : m_table_list)
		i.second->Dump(fio, type);
}
#endif